package com.mb.microservice.framework.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * @program: Fabric-http
 * @description:
 * @author: wys1890
 * @create: 2020-11-12 08:37
 **/
@Slf4j
public class CommonUtils {
    
    
    /**
     * @param obj        : 被解析对象
     * @param fieldNames : 忽略属性
     * @return : java.lang.String[] 返回对象的属性列表
     * @Description : 解析对象属性
     * @author Eibons
     * @date 2020/11/12 8:43
     */
    public static String[] getParams(Object obj, String... fieldNames) {
        if (obj == null) {
            return null;
        }
        List<String> fieldNameList;
        if (fieldNames != null) {
            int len = fieldNames.length;
            fieldNameList = new ArrayList<>(len);
            int i = 0;
            for (; i < len; i++) {
                fieldNameList.add(fieldNames[i]);
            }
        } else {
            fieldNameList = new ArrayList<>();
        }
        List<String> params = new ArrayList<>();
        Class c = obj.getClass();
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            String name = field.getName();
            String fieldNameCurr = fieldNameList.stream().filter(fieldName -> name.equals(fieldName)).findFirst().orElse(null);
            if (StringUtils.isNotBlank(fieldNameCurr)) {
                continue;
            }
            try {
                field.setAccessible(true);
                Object value = field.get(obj);
                if (value != null && StringUtils.isNotBlank(value.toString())) {
                    params.add(value.toString());
                } else {
                    params.add("");
                }
            } catch (IllegalAccessException e) {
                log.error(e.getMessage(), e);
            }
        }
        if (params.size() > 0) {
            return params.toArray(new String[params.size()]);
        }
        return null;
    }
    
    public static String[] getParams(Object obj) {
        try {
            if (obj == null) {
                return null;
            }
            List<String> params = new ArrayList<>();
            Class c = obj.getClass();
            Field[] fields = c.getDeclaredFields();
            for (Field field : fields) {
                int m = field.getModifiers();
                //public 或 transient 或 static 或 final 修饰的属性不作为参数返回
                if (Modifier.isPublic(m) || Modifier.isTransient(m) || Modifier.isStatic(m) || Modifier.isFinal(m)) {
                    continue;
                }
                field.setAccessible(true);
                Object value = field.get(obj);
                if (value != null && StringUtils.isNotBlank(value.toString())) {
                    params.add(value.toString());
                } else {
                    params.add("");
                }
            }
            
            if (params.size() > 0) {
                return params.toArray(new String[params.size()]);
            }
        } catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
    
    
    /**
     * @param file  : 上传的excel文件
     * @param clazz : 返回类型
     * @Description : 导入excel解析, 传入的实例对象属性顺序务必与excel的列从左到右一一对应
     * @author Eibons
     * @date 2020/11/9 11:10
     */
    public static List getDataFromExcel(MultipartFile file, Class clazz) throws IOException {
        String fileName = file.getOriginalFilename();
        if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
            throw new IOException("上传文件格式不正确");
        }
        Workbook workbook = null;
        try {
            InputStream is = file.getInputStream();
            //根据指定的文件输入流导入Excel从而产生Workbook对象
            if (fileName.endsWith(Constants.EXCEL2003)) {
                workbook = new HSSFWorkbook(is);
            }
            if (fileName.endsWith(Constants.EXCEL2007)) {
                workbook = new XSSFWorkbook(is);
            }
            if (workbook != null) {
                List list = new ArrayList<>();
                //  返回封装对象实例
                Object instance;
                //  循环遍历Excel文档中的第startSheet开始所有表单
                for (Sheet sheet : workbook) {
                    //对Sheet中的每一行进行迭代
                    Iterator<Row> rowIterator = sheet.rowIterator();
                    // 跳过首行
                    if (rowIterator.hasNext()) {
                        rowIterator.next();
                    }
                    while (rowIterator.hasNext()) {
                        Row row = rowIterator.next();
                        instance = assignField(clazz, row);
                        list.add(instance);
                    }
                }
                if (!list.isEmpty()) {
                    return list;
                }
            }
            return null;
        } catch (Exception e) {
            log.error(String.format("parse excel exception!"), e);
            return null;
        } finally {
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (Exception e) {
                    log.error(String.format("parse excel exception!"), e);
                }
            }
        }
    }
    
    
    /**
     * @param clazz : 实体的class对象
     * @param row   : excel行内容
     * @return : java.lang.Object
     * @Description : excel的一行数据与实体的属性一一对应赋值
     * @author Eibons
     * @date 2020/11/12 14:09
     */
    private static Object assignField(Class clazz, Row row)
            throws IllegalAccessException, InstantiationException, NoSuchFieldException {
        Object instance = clazz.newInstance();
        Field[] fields = clazz.getDeclaredFields();
        if (fields.length == 0) {
            throw new NoSuchFieldException();
        }
        for (int i = 0; i < fields.length; i++) {
            // 遍历每一列并且给对象属性赋值
            Field filed = fields[i];
            filed.setAccessible(true);
            Cell cell = row.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
            CellType cellType = cell.getCellType();
            switch (cellType) {
                case BLANK:
                case STRING:
                    filed.set(instance, cell.getStringCellValue());
                    break;
                case NUMERIC:
                case FORMULA:
                    double value = cell.getNumericCellValue();
                    if (DateUtil.isCellDateFormatted(cell)) {
                        Date date = DateUtil.getJavaDate(value);
                        filed.set(instance, DateUtils.timestamp2DateStr(date.getTime()));
                        break;
                    }
                    filed.set(instance, String.valueOf(value));
                    break;
                case BOOLEAN:
                    filed.set(instance, String.valueOf(cell.getBooleanCellValue()));
                    break;
                case ERROR:
                default:
                    throw new IllegalArgumentException("无法识别当前单元格格式");
            }
        }
        return instance;
    }
    
    
}
